<template>
  <div class="drawerWrap add-database-drawer mx5">
    <div>
      <el-form
        class="p-20px"
        ref="formRef"
        :model="formOption.data"
        :rules="rules"
        label-width="150px"
      >
        <el-form-item label="数据源名称:" prop="name">
          <ns-input
            :rows="6"
            type="text"
            v-model.trim="formOption.data.name"
            placeholder="请输入数据源名称"
            :maxlength="50"
          />
        </el-form-item>
        <el-form-item label="归属机构:" prop="deptId">
          <el-cascader
            ref="deptCascader"
            v-model="formOption.data.deptId"
            placeholder="请选择归属机构"
            :props="formOption.cascaderProps"
            :options="deptList"
            filterable
            value-on-clear=""
            clearable
            :filter-method="sysFilterMethod"
          />
        </el-form-item>
        <el-form-item label="归属系统:" prop="sysId" style="margin-bottom: 10px">
          <el-cascader
            ref="systemCascader"
            v-model="formOption.data.sysId"
            placeholder="请选择归属系统"
            :props="formOption.systemCascaderProps"
            :options="formOption.systemList"
            filterable
            value-on-clear=""
            :filter-method="sysFilterMethod"
            clearable
          />
        </el-form-item>
        <el-form-item style="margin-bottom: 10px">
          <Icon icon="svg-icon:tips" />
          <span style="color: #cccccc">归属机构与归属系统至少填写一项</span>
        </el-form-item>
        <el-form-item label="资产类型:" prop="assetTypeName">
          <el-select
            v-model.trim="formOption.data.assetTypeName"
            class="w-full"
            popper-class="select-no-dropdown"
            placeholder="请选择资产类型"
            :disabled="!props.params.isAdd"
            @click="showAssetSelect"
          />
        </el-form-item>
        <el-form-item
          v-if="dynamicForm.mainOption.show_name && formOption.data.assetTypeName != ''"
          class="col-item"
          :label="`${dynamicForm.mainOption.show_name}:`"
          prop="authType"
        >
          <el-select
            v-model="formOption.data.authType"
            class="w-full"
            :placeholder="dynamicForm.mainOption.show_name"
            :disabled="!props.params.isAdd"
          >
            <el-option
              v-for="(item, index) in authTypeList"
              :key="'authType' + index"
              :label="item.show_val"
              :value="item.req_val"
            />
          </el-select>
        </el-form-item>
        <DynamicForm
          ref="dynamicFormRef"
          v-if="formOption.data[dynamicForm.mainOption.req_name]"
          :option="dynamicForm.optionType[formOption.data[dynamicForm.mainOption.req_name]]"
          :sqlName="activeAssetInfo.name"
          :defaulePort="
            formOption.data[dynamicForm.mainOption.req_name] && props.params.isAdd
              ? activeAssetInfo.defaultPort
              : ''
          "
          :info="dynamicInfo"
          :isAdd="props.params.isAdd"
          :configStatus="configStatus"
        />
        <template v-if="formOption.data.assetTypeName != ''">
          <el-form-item label="扫描引擎" prop="deviceId">
            <el-select
              v-model="formOption.data.deviceId"
              @focus="getEngineList"
              clearable
              placeholder="请选择扫描引擎"
            >
              <o-option-group v-loading="scanLoading" label="扫描引擎">
                <el-option
                  v-for="item in engineList"
                  :key="item.ip"
                  :label="item.deviceName || item.deviceId"
                  :value="item.ip"
                  :disabled="!item.telnet || item.pingValue == '-1' || item.pingValue == ''"
                >
                  <template #default>
                    <div class="float-left">{{ item.deviceName || item.deviceId }}</div>
                    <div
                      v-if="item.telnet && item.pingValue != '-1' && item.pingValue != ''"
                      class="succeed-text float-right"
                      >{{ item.pingValue + 'ms' }}</div
                    >
                    <div v-else class="fail-text float-right">请求超时</div>
                  </template>
                </el-option>
              </o-option-group>
            </el-select>
          </el-form-item>
          <el-form-item label="验证结果:" style="margin-bottom: 5px">
            <el-button @click="valid" :loading="loading">登录验证</el-button>
          </el-form-item>
          <el-form-item label="">
            <el-button
              v-if="formOption.data.configStatus > -1"
              :type="formOption.data.configStatus ? 'success' : 'danger'"
              size="default"
              text
            >
              {{ formOption.data.configStatus ? '已通过' : '未通过' }}
            </el-button>
          </el-form-item>
          <template v-if="props.params?.source == 'dbSource' || !props.params">
            <el-form-item label="系统库处置:" prop="filterSys">
              <el-radio-group v-model="formOption.data.filterSys" class="ml-4">
                <el-radio :label="0">扫描时保留系统库</el-radio>
                <el-radio :label="1">扫描时过滤系统库</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="扫描范围设置:" prop="scanScope">
              <el-radio-group v-model="formOption.data.scanScope" class="ml-4">
                <el-radio :label="1">全部</el-radio>
                <el-radio :label="2">自定义设置</el-radio>
              </el-radio-group>
            </el-form-item>
            <template v-if="formOption.data.scanScope === 2"
              ><el-form-item label="范围设置:" prop="scopeType">
                <el-radio-group
                  v-model="formOption.data.scopeType"
                  class="ml-4"
                  @change="clearRange"
                >
                  <el-radio :label="1">按库</el-radio>
                  <el-radio :label="2">按schema</el-radio>
                  <el-radio :label="3">按表</el-radio>
                </el-radio-group>
              </el-form-item>
              <el-form-item label="范围:" prop="scopeRange">
                <el-select
                  v-model.trim="formOption.data.scopeRange"
                  class="w-full"
                  popper-class="select-no-dropdown"
                  placeholder="请选择范围"
                  multiple
                  @click="showScopeRange"
                  @change="changeRangeList"
                /> </el-form-item
            ></template>
          </template>
        </template>
      </el-form>
    </div>
    <div class="dialog-footer">
      <el-button type="primary" @click="submit">确 定</el-button>
      <el-button @click="cancel">取 消</el-button>
    </div>
    <asset-select
      v-model="assetOption.show"
      v-if="assetOption.show"
      :type="props.params.source"
      @update-asset-type="updateAssetType"
    />
    <scope-range-list
      v-model="scopeRangeOption.show"
      v-if="scopeRangeOption.show"
      :type="formOption.data.scopeType"
      :connection="connectionInfo"
      :selectInfo="formOption.data.scopeRange"
      @update="updateScopeRange"
      :filterSys="formOption.data.filterSys.toString()"
      :isScan="formOption.data.deviceId.length > 0"
      :deviceId="formOption.data.deviceId"
    />
  </div>
</template>

<script lang="ts" setup>
import { getMetaInfoPage } from '@/api/asset/taskManage/dataCollect'
import { cloneDeep } from 'lodash-es'
import { getSimpleDeptList } from '@/api/system/dept'
import { getConnectConfig } from '@/api/asset/taskManage/dataCollect'
import { dbVerify, enginePingList } from '@/api/asset/taskManage/dataCollect'
import * as api from '@/api/asset/taskManage'
import { createDataSource, updateDataSource } from '@/api/dataSourceManage/index'
import DynamicForm from './DynamicForm.vue'
import assetSelect from './AssetSelect.vue'
import ScopeRangeList from './ScopeRangeList.vue'
import { reactiveComputed } from '@vueuse/core'
import { SM4Encrypt } from '@/utils/sm4Util'
import { handleTree } from '@/utils/tree'
import { ElMessage } from 'element-plus'
import { sysFilterMethod } from '@/utils/selectFilter'

const { proxy } = getCurrentInstance()
const formRef = ref()
const deptCascader = ref()
const systemCascader = ref()
const dynamicFormRef = ref(null)
const scanLoading = ref(false)
const emit = defineEmits(['update:model-value', 'submit'])
const props = defineProps(['params', 'closeOutDrawer'])
const assetOption = reactive({
  show: false
})
const scopeRangeOption = reactive({
  show: false
})
const engineList = ref([])
let activeAssetInfo = ref({})
const authTypeList = ref([])
const loading = ref(false)
let dynamicForm = reactive({
  authTypeAppRelation: {},
  mainOption: {},
  specialSql: [],
  optionType: {}
})
const dataTypeList = reactive({
  1: 'db',
  3: 'table',
  2: 'schema'
})
const dynamicInfo = ref({})
const deptList = ref<Tree[]>([]) // 树形结构
const formOption = reactive({
  data: {
    name: '',
    deptId: '',
    sysId: '',
    scanMethod: 0,
    assetType: '',
    assetTypeName: '',
    authType: '',
    connectionInfo: {},
    configStatus: 0,
    scanFilePath: '',
    scanScope: 1,
    scopeType: 1,
    filterSys: 0,
    scopeRange: [],
    deviceId: ''
  },
  systemList: [],
  cascaderProps: {
    checkStrictly: true,
    label: 'name',
    value: 'id',
    children: 'children',
    emitPath: false
  },
  systemCascaderProps: {
    checkStrictly: true,
    label: 'value',
    value: 'id',
    children: 'children',
    emitPath: false
  }
})
const isRequired = computed(() => {
  return !formOption.data.deptId && !formOption.data.sysId
})
const rules = computed(() => ({
  name: [{ required: true, message: '数据源名称不能为空', trigger: 'blur' }],
  sysId: [{ required: isRequired.value, message: '归属系统不能为空', trigger: 'change' }],
  deptId: [{ required: isRequired.value, message: '归属机构不能为空', trigger: 'change' }],
  scanMethod: [{ required: true, message: '请选择扫描方式', trigger: 'change' }],
  scanFilePath: [{ required: true, message: '扫描路径不能为空', trigger: 'blur' }],
  assetTypeName: [{ required: true, message: '资产类型不能为空', trigger: 'change' }],
  authType: [{ required: true, message: '认证类型不能为空', trigger: 'change' }],
  scanScope: [{ required: true, message: '请选择扫描范围', trigger: 'change' }],
  filterSys: [{ required: true, message: '请选择系统处置库操作', trigger: 'change' }],
  scopeType: [{ required: true, message: '请设置扫描范围', trigger: 'change' }],
  scopeRange: [{ required: true, message: '请选择范围', trigger: 'change' }],
  deviceId: [{ required: true, message: '请选择扫描引擎', trigger: 'change' }]
}))
function valid() {
  if (dynamicFormRef.value) {
    dynamicFormRef.value.formRef.validate((dynamicValid) => {
      if (dynamicValid) {
        handleVerify()
      }
    })
  }
}
async function handleVerify() {
  const formData = cloneDeep(dynamicFormRef.value.form)
  for (const k in formData) {
    if (
      k.indexOf('password') > -1 ||
      k.indexOf('Password') > -1 ||
      k.indexOf('dbAccount') > -1 ||
      k.indexOf('userName') > -1
    )
      formData[k] = SM4Encrypt(formData[k])
  }
  const params = Object.assign({}, formData, {
    authType: formOption.data.authType,
    connectType: formData.connectType
  })
  loading.value = true
  const data = await dbVerify({
    appType: activeAssetInfo.value.name,
    authType: formOption.data.authType,
    connectType: formData.connectType,
    isDefault: 1,
    deviceId: formOption.data.deviceId,
    params: params
  }).catch(() => {
    loading.value = false
  })
  if (!data.connect) {
    ElMessage.error('验证未通过:' + data.msg)
    formOption.data.configStatus = 0
  } else {
    formOption.data.configStatus = 1
  }
  loading.value = false
}
function getEngineList() {
  if (dynamicFormRef.value) {
    dynamicFormRef.value.formRef.validate((dynamicValid) => {
      if (dynamicValid) {
        const formData = cloneDeep(dynamicFormRef.value.form)
        for (const k in formData) {
          if (
            k.indexOf('password') > -1 ||
            k.indexOf('Password') > -1 ||
            k.indexOf('dbAccount') > -1 ||
            k.indexOf('userName') > -1
          )
            formData[k] = SM4Encrypt(formData[k])
        }
        const params = Object.assign({}, formData, {
          authType: formOption.data.authType,
          connectType: formData.connectType
        })
        scanLoading.value = true
        enginePingList({
          appType: activeAssetInfo.value.name,
          authType: formOption.data.authType,
          connectType: formData.connectType,
          isDefault: 1,
          params: params
        })
          .then((res) => {
            engineList.value = res.data
            scanLoading.value = false
          })
          .catch(() => {
            scanLoading.value = false
          })
      }
    })
  } else if (!props?.params?.isAdd && dynamicInfo.value.ip && dynamicInfo.value.port) {
    const formData = cloneDeep(dynamicInfo.value)
    for (const k in formData) {
      if (
        k.indexOf('password') > -1 ||
        k.indexOf('Password') > -1 ||
        k.indexOf('dbAccount') > -1 ||
        k.indexOf('userName') > -1
      )
        formData[k] = SM4Encrypt(formData[k])
    }
    const params = Object.assign({}, formData, {
      authType: formOption.data.authType,
      connectType: formData.connectType
    })
    scanLoading.value = true
    enginePingList({
      appType: activeAssetInfo.value.name,
      authType: formOption.data.authType,
      connectType: formData.connectType,
      isDefault: 1,
      params: params
    })
      .then((res) => {
        engineList.value = res.data
        scanLoading.value = false
      })
      .catch(() => {
        scanLoading.value = false
      })
  }
}
function submit() {
  formRef.value.validate((valid) => {
    if (dynamicFormRef.value) {
      dynamicFormRef.value.formRef.validate((dynamicValid) => {
        if (valid && dynamicValid) {
          handleSubmit()
        }
      })
    } else if (valid) {
      handleSubmit()
    }
  })
}

const filterData = () => {
  const formData = dynamicFormRef.value.form
  const {
    name,
    assetTypeName,
    deptId,
    sysId,
    scanMethod,
    scanFilePath,
    authType,
    configStatus,
    scanScope,
    filterSys,
    scopeType,
    scopeRange
  } = formOption.data
  let scanParam = {}
  let scanScopeParam = {}
  const deptCheckedNodes = deptCascader.value.getCheckedNodes()
  const systemCheckedNodes = systemCascader.value.getCheckedNodes()
  if (activeAssetInfo.value.category1 === '文件服务' && scanMethod) {
    scanParam = { scanFilePath: scanFilePath }
  }
  if (scanScope === 1) {
    scanScopeParam = {
      scanScope: scanScope,
      filterSys: filterSys
    }
  } else if (scanScope === 2) {
    scanScopeParam = {
      scanScope: scanScope,
      scopeType: scopeType,
      scopeRange: formOption.data.scopeRange.join()
    }
  }
  const params = Object.assign({}, formData, {
    authType: authType,
    connectType: formData.connectType
  })
  const rowData = {
    name: name,
    ip: formData.ip || '',
    port: formData.port || '',
    assetType: activeAssetInfo.value.name,
    assetTypeName: assetTypeName,
    dbName: formData.default_db_name || '',
    deptId: deptId,
    sysId: sysId,
    department: deptCheckedNodes[0]?.pathLabels?.reverse().join(' / '),
    system: systemCheckedNodes[0]?.pathLabels?.reverse().join(' / '),
    configStatus: configStatus,
    ...scanParam,
    ...scanScopeParam,
    connectionInfo: {
      appType: activeAssetInfo.value.name,
      authType: authType,
      connectType: formData.connectType,
      isDefault: 1,
      params: params
    }
  }
  return rowData
}

async function handleSubmit() {
  const rowData = filterData()
  for (const k in rowData.connectionInfo.params) {
    if (
      k.indexOf('password') > -1 ||
      k.indexOf('Password') > -1 ||
      k.indexOf('dbAccount') > -1 ||
      k.indexOf('userName') > -1
    )
      rowData.connectionInfo.params[k] &&
        (rowData.connectionInfo.params[k] = SM4Encrypt(rowData.connectionInfo.params[k]))
  }
  if (typeof rowData.scopeRange == 'object' && rowData.scopeRange.length != 0) {
    rowData.scopeRange = rowData.scopeRange.join()
  }
  if (!props.params.isConfig) {
    const { code } = props.params.isAdd
      ? await createDataSource({
          ...rowData,
          datasourceType: props.params.source === 'dbSource' ? 1 : 2,
          deviceId: formOption.data.deviceId
        })
      : await updateDataSource({
          ...rowData,
          id: props.params.info.id,
          datasourceType: props.params.source === 'dbSource' ? 1 : 2,
          deviceId: formOption.data.deviceId
        })
    if (code === 200) {
      ElMessage.success(props.params.isAdd ? '新建成功' : '编辑成功')
      props.params.callBack()
      cancel()
    }
  } else {
    if (!formOption.data.configStatus) {
      ElMessage.error('请先通过验证')
      return
    }
    ElMessage.success('配置连接信息成功')
    console.log(props.params.info)

    props.params?.callBack({
      ...props.params.info,
      ...rowData,
      datasourceId: props.params.info.datasourceId,
      deviceId: formOption.data.deviceId,
      id: props.params.info.id,
      dbName: rowData.connectionInfo.params.defaultDbName
    })
    const { code } = await updateDataSource({
      ...rowData,
      id: props.params.info.datasourceId || props.params.info.id,
      datasourceType: props.params.source === 'dbSource' ? 1 : 2,
      deviceId: formOption.data.deviceId
    })
    if (code === 200) {
      cancel()
    }
  }
  cancel()
}
function cancel() {
  props.closeOutDrawer()
}

function clearRange() {
  formOption.data.scopeRange = []
}

function showAssetSelect() {
  props.params.isAdd && (assetOption.show = true)
}
function updateAssetType(sql) {
  formOption.data.assetTypeName = sql.showName
  activeAssetInfo.value = sql
  assetOption.show = false
  getAuthTypeList()
}
const connectionInfo = ref()
function showScopeRange() {
  if (formOption.data.assetTypeName == '') {
    ElMessage.error('请先选择资产类型')
    return
  }
  const data = filterData()
  connectionInfo.value = data.connectionInfo
  scopeRangeOption.show = true
}
function updateScopeRange(rows) {
  formOption.data.scopeRange = cloneDeep(rows)
}

function getAuthTypeList() {
  if (formOption.data.assetTypeName) {
    let flag = false
    for (const k in dynamicForm.specialSql) {
      const key = dynamicForm.specialSql[k]
      if (key.toLocaleLowerCase() == activeAssetInfo.value.name.toLocaleLowerCase()) {
        authTypeList.value = dynamicForm.authTypeAppRelation[key] || []
        flag = true
      }
    }
    if (!flag) {
      authTypeList.value = dynamicForm.mainOption.optionList || []
    }
    formOption.data[dynamicForm.mainOption.req_name] = authTypeList.value[0]?.req_val
  }
}
const configStatus = () => {
  formOption.data.configStatus = 0
}
async function getConfig() {
  const data = await getConnectConfig()
  dynamicForm.authTypeAppRelation = data.interact_config.authTypeAppRelation
  dynamicForm.mainOption = data.show_config.mainOption
  dynamicForm.specialSql = Object.keys(dynamicForm.authTypeAppRelation)
  dynamicForm.optionType = data.show_config.optionType
  authTypeList.value = dynamicForm.mainOption.optionList
  getAuthTypeList()
}

watch(
  props.params.info,
  () => {
    if (!props.params.isAdd) {
      formOption.data = cloneDeep(props.params.info)
      formOption.data.scanMethod = Number(!!formOption?.data?.scanFilePath)
      if (formOption.data.scopeRange) {
        formOption.data.scopeRange = formOption.data.scopeRange.split(',')
      }
      if (![1, 2, 3].includes(formOption.data.scopeType)) {
        formOption.data.scopeType = 1
      }
      formOption.data.deptId = formOption.data.deptId == '0' ? '' : formOption.data.deptId
      if (props.params.info.assetTypeName) {
        formOption.data.authType = props.params.info.connectionInfo?.authType
        dynamicInfo.value = props.params.info.connectionInfo?.params
          ? cloneDeep(props.params.info.connectionInfo.params)
          : { ip: props.params.info.ip, port: props.params.info.port }
      } else {
        dynamicInfo.value = {
          ip: formOption.data.ip,
          port: formOption.data.port
        }
      }
      dynamicInfo.value.default_db_name =
        props.params.info.connectionInfo?.params?.default_db_name || ''

      activeAssetInfo.value = {
        showName: formOption.data.assetTypeName,
        name: formOption.data.assetType || formOption.data.connectionInfo?.appType,
        category1: formOption.data.category
      }
      getAuthTypeList()
      engineList.value = [
        { ip: props.params.info.deviceId, deviceName: props.params.info.deviceName }
      ]
      getEngineList()
    }
  },
  { immediate: true }
)
async function getDeptList() {
  const data = await getSimpleDeptList()
  deptList.value = data
}
async function getSystemList() {
  const data = await api.getSimpleSystemList()
  formOption.systemList = handleTree(data, 'id', 'pid')
}
onMounted(() => {
  getDeptList()
  getSystemList()
  getConfig()
})
</script>
<style lang="scss">
.add-database-drawer {
  .el-cascader {
    width: 100%;
  }
}
.select-no-dropdown {
  display: none;
}
.fail-text {
  color: rgb(250, 89, 89);
}
.succeed-text {
  color: #67c23a;
}
</style>
